
/**
 * 优化版喷泉码(LT码)实现
 * 包含鲁棒孤子分布、高效解码和渐进式解码功能
 */
export default class FountainCode {
    constructor() {
        this.prime = 257; // 用于GF(256)运算的素数
        this.epsilon = 0.1; // 鲁棒孤子分布参数
    }

    /**
     * 将原始数据分块
     * @param {string|Uint8Array} data 原始数据
     * @param {number} blockSize 每块大小(字节)
     * @returns {Uint8Array[]} 分块后的字节数组列表
     */
    splitData(data, blockSize) {
        let dataBytes;

        if (typeof data === "string") {
            dataBytes = new TextEncoder().encode(data);
        } else if (data instanceof Uint8Array) {
            dataBytes = data;
        } else {
            throw new Error("数据类型必须是字符串或Uint8Array");
        }

        const blocks = [];
        const totalBlocks = Math.ceil(dataBytes.length / blockSize);

        for (let i = 0; i < totalBlocks; i++) {
            const block = new Uint8Array(blockSize);
            const chunk = dataBytes.subarray(
                i * blockSize,
                (i + 1) * blockSize
            );
            block.set(chunk);
            blocks.push(block);
        }

        return blocks;
    }

    /**
     * 计算鲁棒孤子分布的参数
     * @param {number} k 原始数据包数量
     * @returns {number[]} 分布概率数组
     */
    calculateRobustSolitonDistribution(k) {
        const c = 0.1; // 常数参数
        const delta = 0.5; // 失败概率
        const R = c * Math.log(k / delta) * Math.sqrt(k); // 鲁棒参数

        const tau = new Array(k + 1).fill(0);
        const rho = new Array(k + 1).fill(0);
        const mu = new Array(k + 1).fill(0);

        // 计算 rho 分布
        rho[1] = 1 / k;
        for (let d = 2; d <= k; d++) {
            rho[d] = 1 / (d * (d - 1));
        }

        // 计算 tau 分布
        for (let d = 1; d < Math.floor(k / R); d++) {
            tau[d] = R / (d * k);
        }
        tau[Math.floor(k / R)] = (R * Math.log(R / delta)) / k;

        // 归一化常数
        let sum = 0;
        for (let d = 1; d <= k; d++) {
            sum += rho[d] + tau[d];
        }

        // 计算最终分布
        for (let d = 1; d <= k; d++) {
            mu[d] = (rho[d] + tau[d]) / sum;
        }

        return mu;
    }

    /**
     * 根据鲁棒孤子分布生成度
     * @param {number} k 原始数据包数量
     * @param {number[]} distribution 分布概率数组
     * @returns {number} 生成的度
     */
    generateDegree(k, distribution) {
        const x = Math.random();
        let sum = 0;

        for (let d = 1; d <= k; d++) {
            sum += distribution[d];
            if (x < sum) {
                return d;
            }
        }

        return k; // 理论上不会执行到这里
    }

    /**
     * 从原始数据包中随机选择几个进行异或操作，生成编码包
     * @param {Uint8Array[]} blocks 原始数据包
     * @param {number} degree 度(选择的数据包数量)
     * @param {number} seed 随机种子
     * @returns {Object} 编码包 {data: 编码后的数据, seed: 随机种子, degree: 度, index: 包索引}
     */
    createEncodedBlock(blocks, degree, seed, index, originDataLength) {
        const k = blocks.length;
        const blockSize = blocks[0].length;
        const random = this.getPseudoRandomGenerator(seed);
        const encodedBlock = new Uint8Array(blockSize);

        // 选择参与异或的原始数据包索引
        const selectedIndices = new Set();
        while (selectedIndices.size < degree) {
            const index = Math.floor(random() * k);
            selectedIndices.add(index);
        }

        // 对选中的数据包进行异或操作
        for (const index of selectedIndices) {
            for (let i = 0; i < blockSize; i++) {
                encodedBlock[i] ^= blocks[index][i];
            }
        }

        return {
            data: encodedBlock,
            seed,
            degree,
            index,
            originDataLength,
        };
    }

    /**
     * 生成指定数量的编码包
     * @param {string|Uint8Array} data 原始数据
     * @param {number} blockSize 每块大小
     * @param {number} numBlocks 生成的编码包数量
     * @returns {Object[]} 编码包列表
     */
    encode(data, blockSize, numBlocks) {
        const blocks = this.splitData(data, blockSize);
        const k = blocks.length;
        const encodedBlocks = [];

        // 计算鲁棒孤子分布
        const distribution = this.calculateRobustSolitonDistribution(k);

        for (let i = 0; i < numBlocks; i++) {
            const degree = this.generateDegree(k, distribution);
            const seed = Math.floor(Math.random() * 1000000);
            const encodedBlock = this.createEncodedBlock(
                blocks,
                degree,
                seed,
                i,
                data.length,
            );
            encodedBlocks.push(encodedBlock);
        }

        return encodedBlocks;
    }

    /**
     * 创建解码器实例
     * @param {number} k 原始数据包数量
     * @param {number} blockSize 每块大小
     * @returns {Object} 解码器对象
     */
    createDecoder(k, blockSize) {
        return new FountainDecoder(k, blockSize);
    }

    /**
     * 将解码后的块合并为原始数据
     * @param {Uint8Array[]} blocks 解码后的块
     * @param {number} originalSize 原始数据大小
     * @returns {Uint8Array} 原始数据
     */
    mergeBlocks(blocks, originalSize) {
        const result = new Uint8Array(originalSize);
        let offset = 0;
        
        for (const block of blocks) {
        // 计算实际需要复制的字节数（处理最后一块可能的填充）
        const copySize = Math.min(block.length, originalSize - offset);
        result.set(block.subarray(0, copySize), offset);
        offset += copySize;
        
        if (offset >= originalSize) {
            break;
        }
        }
        
        return result;
    }

    /**
     * 伪随机数生成器
     * @param {number} seed 随机种子
     * @returns {function} 返回生成0-1之间随机数的函数
     */
    getPseudoRandomGenerator(seed) {
        let x = seed;
        return () => {
            // 使用更复杂的Xorshift算法提高随机性
            x ^= x << 13;
            x ^= x >> 17;
            x ^= x << 5;
            return (x >>> 0) / 4294967296;
        };
    }
}
